package com.katze.boot.plugins.redis.operations;


import com.katze.boot.plugins.redis.RedisTemplateManager;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;

/**
 * 说  明：Redis 对Key-Map操作的封装
 * 作  者：zf.zeng
 * 日  期：2021-02-14 (星期日)
 **/
public class RedisHashOperations<V> {

    private final HashOperations<String, String, V> hashOperations;
    private RedisTemplateManager<V> manager;

    public RedisHashOperations(RedisTemplate<String, V> redisTemplate) {
        this.hashOperations = redisTemplate.opsForHash();
    }

    public RedisHashOperations(RedisTemplateManager<V> manager) {
        this.manager = manager;
        this.hashOperations = manager.primary().opsForHash();
    }

    public <R>R select(int database, Function<HashOperations<String, String, V>, R> function){
        return function.apply(database < 0? this.hashOperations:this.manager.select(database).opsForHash());
    }

    /**
     * 获取集合中的某个值
     *
     * @param key     集合键
     * @param hashKey 集合键中的hashkey
     */
    public V get(String key, String hashKey) {
        return this.hashOperations.get(key, hashKey);
    }

    /**
     * 获取key下的所有hashkey字段名
     *
     * @param key 集合键
     */
    public Set<String> keys(String key) {
        return this.hashOperations.keys(key);
    }

    /**
     * 获取key下的所有hashValue
     *
     * @param key 集合键
     */
    public List<V> values(String key) {
        return this.hashOperations.values(key);
    }

    /**
     * 获取集合中的所有元素
     *
     * @param key 集合键
     */
    public Map<String, V> entries(String key) {
        return this.hashOperations.entries(key);
    }

    /**
     * 添加hash键值对
     *
     * @param key       集合键
     * @param hashKey   集合键中的hashkey
     * @param hashValue 值
     */
    public void put(String key, String hashKey, V hashValue) {
        this.hashOperations.put(key, hashKey, hashValue);
    }

    /**
     * 添加hash键值对
     * 如果不存在则添加
     *
     * @param key     集合键
     * @param hashKey 集合键中的hashkey
     * @param value   值
     */
    public Boolean putIfAbsent(String key, String hashKey, V value) {
        return this.hashOperations.putIfAbsent(key, hashKey, value);
    }

    /**
     * 批量添加hash的键值对
     * 如果有则覆盖,反之则添加
     *
     * @param key 集合键
     * @param map hash
     */
    public void putAll(String key, Map<String, V> map) {
        this.hashOperations.putAll(key, map);
    }

    /**
     * 删除指定hash的HashKey
     *
     * @param key      集合键
     * @param hashKeys 集合键中的hashkey
     * @return 删除成功的 数量
     */
    public Long delete(String key, Object... hashKeys) {
        return this.hashOperations.delete(key, hashKeys);
    }

    /**
     * 给指定hash的hashkey做增减操作
     *
     * @param key     集合键
     * @param hashKey 集合键中的hashkey
     * @param number  长整型数值
     */
    public Long increment(String key, String hashKey, long number) {
        return this.hashOperations.increment(key, hashKey, number);
    }

    /**
     * 给指定 hash的hashkey做增减操作
     *
     * @param key     集合键
     * @param hashKey 集合键中的hashkey
     * @param number  双精度数值
     */
    public Double increment(String key, String hashKey, Double number) {
        return this.hashOperations.increment(key, hashKey, number);
    }

    /**
     * 验证指定key下有没有指定hashkey
     *
     * @param key     集合键
     * @param hashKey 集合键中的hashkey
     */
    public Boolean hashKey(String key, String hashKey) {
        return this.hashOperations.hasKey(key, hashKey);
    }

    /**
     * 获取指定hash下面的键值对数量
     *
     * @param key 集合键
     */
    public Long size(String key) {
        return this.hashOperations.size(key);
    }

    /**
     * 扫描指定key下的所有元素
     *
     * @param key 集合键
     */
    public Map<String, V> scan(String key) {
        return this.scan(key, "*");
    }

    /**
     * 扫描指定key下的数据集
     *
     * @param key      集合键
     * @param matchKey 匹配关键字 模糊查询：*123，*
     */
    public Map<String, V> scan(String key, String matchKey) {
        Map<String, V> data = new LinkedHashMap<>();
        try (Cursor<Map.Entry<String, V>> cursor = this.hashOperations.scan(key, ScanOptions.scanOptions().match(matchKey).count(1000).build())) {
            while (cursor.hasNext()) {
                Map.Entry<String, V> entry = cursor.next();
                data.put(entry.getKey(), entry.getValue());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }
}
